`timescale 1ns/100ps

module cm_fft2_output_change #(
    parameter C_DATA_WIDTH = 16, // 数据位宽
    parameter C_ADDR_NUM   = 4  // FFT点数为 2^C_ADDR_NUM
)(
    input  wire                     I_sys_clk,       // 工作时钟 100M
    input  wire                     I_data_start,    // 数据开始进入标志，与第一个数据对齐输入
    input  wire [C_DATA_WIDTH-1:0]  I_data_in_real,  // 数据输入（实部），从start开始连续输入
    input  wire [C_DATA_WIDTH-1:0]  I_data_in_imag,  // 数据输入（虚部），从start开始连续输入
    output wire                     O_data_start,    // 数据开始输出标志，与第一个数据对齐输出
    output wire [C_DATA_WIDTH-1:0]  O_data_out_real, // 数据输出（实部），位宽按照最大能力输出
    output wire [C_DATA_WIDTH-1:0]  O_data_out_imag  // 数据输出（虚部），位宽按照最大能力输出
);

// ============================================================
// 内部参数
// ============================================================
localparam C_DATA_NUM = 2 ** C_ADDR_NUM; // FFT数据点数

// ============================================================
// 变量声明
// ============================================================
reg                         S_pingpang_flag;     // Ping-Pong缓冲区切换标志
reg  [C_ADDR_NUM:0]         S_wr_addr;           // 写地址计数器
wire                        S_wr_en;             // 写使能信号
reg  [C_DATA_WIDTH*2-1:0]   S_data_in;           // 输入数据拼接（实部+虚部）
reg  [C_ADDR_NUM-1:0]       S_rd_addr;           // 读地址计数器
wire                        S_change_start;      // 地址切换启动信号
reg  [C_ADDR_NUM-1:0]       S_data_cnt;          // 数据计数器
reg                         S_start_d1;          // 延迟信号1
reg                         S_start_d2;          // 延迟信号2
reg                         S_start_d3;          // 延迟信号3
reg                         S_pingpang_flag_rd;  // 读取Ping-Pong标志

// ============================================================
// 主逻辑代码
// ============================================================

// 切换Ping-Pong缓冲区标志
always @(posedge I_sys_clk) begin
    if (I_data_start)
        S_pingpang_flag <= ~S_pingpang_flag;
    else
        S_pingpang_flag <= S_pingpang_flag;
end

// 写地址计数器
always @(posedge I_sys_clk) begin
    if (I_data_start)
        S_wr_addr <= 'b0;
    else if (S_wr_en)
        S_wr_addr <= S_wr_addr + 'd1;
    else
        S_wr_addr <= S_wr_addr;
end

// 写使能信号生成
assign S_wr_en = ~S_wr_addr[C_ADDR_NUM];

// 拼接输入数据（实部+虚部）
always @(posedge I_sys_clk) begin
    S_data_in <= {I_data_in_real, I_data_in_imag};
end

// 地址切换启动信号
assign S_change_start = ({S_wr_addr[C_ADDR_NUM-1], |S_wr_addr[C_ADDR_NUM-2:0]} == 2'b10);

// 数据计数器
always @(posedge I_sys_clk) begin
    if (S_change_start)
        S_data_cnt <= 'd0;
    else
        S_data_cnt <= S_data_cnt + 'd1;
end

// 动态生成读地址反转逻辑
genvar j;
generate
    for (j = 0; j < C_ADDR_NUM; j = j + 1) begin : addr_change
        always @(posedge I_sys_clk) begin
            S_rd_addr[j] <= S_data_cnt[C_ADDR_NUM - j - 1];
        end
    end
endgenerate

// 同步读取Ping-Pong标志
always @(posedge I_sys_clk) begin
    if (S_start_d1)
        S_pingpang_flag_rd <= S_pingpang_flag;
    else
        S_pingpang_flag_rd <= S_pingpang_flag_rd;
end

// 实例化单端口RAM模块
cm_dis_sdp_ram #(
    .C_DATA_WIDTH(C_DATA_WIDTH * 2), // RAM数据宽度
    .C_ADDR_WIDTH(C_ADDR_NUM + 1),  // RAM深度（2^C_ADDR_WIDTH）
    .C_DELAY_NUM(1),                // 延迟
    .INIT_FILE("")                  // 初始化文件（留空表示不使用）
) u0_cm_dis_sdp_ram (
    .I_addra({S_pingpang_flag, S_wr_addr[C_ADDR_NUM-1:0]}), // 写地址
    .I_addrb({S_pingpang_flag_rd, S_rd_addr}),              // 读地址
    .I_dina(S_data_in),                                    // 写入数据
    .I_clka(I_sys_clk),                                    // 写时钟
    .I_clkb(I_sys_clk),                                    // 读时钟
    .I_wea(S_wr_en),                                       // 写使能
    .O_doutb({O_data_out_real, O_data_out_imag})           // 输出数据（实部+虚部）
);

// 启动信号延迟链
always @(posedge I_sys_clk) begin
    S_start_d1 <= S_change_start;
    S_start_d2 <= S_start_d1;
    S_start_d3 <= S_start_d2;
end

// 输出启动信号
assign O_data_start = S_start_d3;

endmodule